Mqtt

您所在的位置:网站首页 micropython 移植 for循环 Mqtt

Mqtt

2024-04-28 07:28| 来源: 网络整理| 查看: 265

Mqtt 概要¶

本节课讲了MQTT协议的特性, MQTT网络里面的组成部分,以及MQTT通信数据传输的流程讲解。

keywords mqtt tcp/ip qos publisher subscriber

MQTT协议简介¶

ESP32是一款物联网(IOT, internet of things)模块. 所谓物联就是机器与机器之间的通信, 互联互通之后,设备之间就可以协同工作。 ESP32作为一个单片机,其网络环境可能是不可靠的, 如果我们采用原始的socket通信,并不能保障信息可以到达接收方,数据的可靠性包括实时性都会有一定的影响, 所以这个时候就需要一种网络通信协议Protocal 来保障信息的传递, 保障服务质量(Qos: Quality of Service)。

互联网的基础网络协议是 TCP/IP。MQTT(消息队列遥测传输) 是基于 TCP/IP 协议栈而构建的,已成为 IoT 通信的标准。

MQTT 是一种轻量级的, 灵活的网络协议,致力于为 IoT 开发人员实现适当的平衡:

这个轻量级协议可在严重受限的设备硬件和高延迟/带宽有限的网络上实现。

它的灵活性使得为 IoT 设备和服务的多样化应用场景提供支持成为可能。

熟悉Web开发的同学,可能会有想法用Http协议来开发物联网应用, 为什么要用MQTT而不是HTTP,可以参考IBM的这篇文章, 讲的比较详细:初识 MQTT-IBM 。

总结下来MQTT有如下特性/优势:

异步消息协议

面向长连接

双向数据传输

协议轻量级

被动数据获取

MQTT的发布和订阅模型¶

MQTT_DHT_02-400x258

注: 图片来自REF 4

在基于MQTT协议的IOT网络里面里面有这么几个角色:

a1

发布者 Publisher 负责发布消息, 例如传感器采集数据,然后发送当前传感器的信息

订阅者 Subscriber 订阅消息,根据获得的传感器数据做出对应的动作。

*服务器 Server * 信息的中转站,负责将信息从发布者传递到订阅者。

其中发布者与订阅者统称为客户端 Client 。

MQTT_DHT_01-400x157

注: 图片来自REF 4

注意, 这个划分并不是说三个角色必须是不同的实体设备,这里只是根据功能划分。有时候一个设备可以同时为发布者或订阅者, 就连服务器自己也可以作为客户端。

注意MQTT是协议,基于TCP/IP, MQTT协议在客户端的实现称之为MQTT Client,

MQTT客户端的各种实现见: mqtt/libs

MQTT协议在服务器端的实现称之为MQTT Broker. MQTT Broker基于各种语言(JAVA, C/C++)的实现,比较流行的MQTT Broker列表见:mqtt server/brokers

为什么MQTT会被广泛用于IOT开发?主要还是归功于它的发布者与订阅者的设计思想。

A3

一个核心思想是,能力越大, 责任越大 .

我们拿PC与单片机举例子,从价格上还有硬件的操控能力,传感器数据读取方面, 单片机更合适, 如果一个地方需要采集100个位点的温度信息,可能会选择使用单片机来读取,那这么多的单片机之间如何进行通信呢?

单片机硬件资源有限(内存,带宽), 就决定了单片机很难与多个客户端进行通信,同时与多个客户端建立长连接。 从内存占用,通信时延, 还有数据的稳定性上来讲,显然我们更相信PC在网络吞吐方面的能力。 另外PC还可以对数据进行数据预处理,然后作为Client发布处理后的数据。

所以根据各自能力的特点, 我们做如下职责划分:

A4

每个单片机(Client)仅与PC(Server)保持一个长连接, 有什么数据就告诉Server, 如果有其他单片机或者PC跟这个单片机通信, 也只能通过这个Server来获取, 同时也要注意,这个数据获取的过程是被动的, 单片机没有主动轮询, 整个过程是异步的, 数据传过来,自动调用回调函数, 所以Server就成了这个单片机与这个周边设备通信的唯一的渠道,这个机制使得整个过程更加轻量级与高效 。

有点像一个地下组织的老大带领着一帮小弟的感觉, 小弟之间互不联系, 直接向老大传递信息, 老大像小弟传递指令。

dataframe

通信所用的数据帧 Data Frame主要由主题编号 Topic ID 还有信息 Message 两部分组成。

发布者与订阅者之间是没办法直接感知到对方的存在的, 订阅者与发布者之间通过数据帧 Data Frame 里面的主题编号Topic ID 来获取自己想要的数据。

MQTT通信流程详细描述¶

举一个远程控制LED灯亮灭的实际例子, 我们这里梳理一下过程。

ESP32与PC连入同一个局域网下, 获取PC 的IP地址

局域网

PC开启 MQTT Broker, 开启Server模式

mqtt broker

ESP32传入PC的IP地址还有端口号,创建一个MQTT_Client

ESP32的MQTT_Client与PC上的MQTT_Server创建一个长连接

ESP32的MQTT_Client 订阅Topic LED_CONTROL

6-4

PC上创建一个CLIENT, Client里面传入本地IP与MQTT Broker服务的端口号, 与PC上面的Server建立一个长连接

img

PC上的Client, 发送数据帧 Topic ID + 指令, Topic ID为LED Control

数据帧: TOPIC_ID: LED_CONTROL, MESSAGE: LED_ON

send dataframe

数据发送给Server, Server发现ESP32开发板订阅了LED_CONTROL 这个主题, 然后就通过ESP32与Server创建的连接发送该数据帧。

ESP32接收到这个数据帧,发现TOPIC_ID: LED_CONTROL, 于是知道这个是跟LED控制相关的指令。

读取到MESSAGE是LED_ON, ESP32执行指令led.on() , LED打开。

led on

读完这篇文章,相信你对MQTT已经跃跃欲试了,下一节课,阿凯带你在局域网下用Python实现MQTT通信。见课程: MQTT入门之项目实战

MQTT实战演练¶ Mosquitto¶ 安装Mosquitto¶

在Ubuntu上面搭建MQTT的开发环境,可以选择Mosquitto, Mosquitto是Eclipse开源的项目, 官网: mosquitto.org。

其中mosquitto就是MQTT Broker的实现, mosquitto-clients是MQTT客户端的实现。

sudo apt-get install mosquitto mosquitto-clients mosquitto_pub¶

-t 代表指定topic

-m 代表message信息

mosquitto_pub -t 'pyespcar_basic_control' -m 'MOVE_FORWARD'

在中端上执行上面的这条信息,等于在主题pyespcar_basic_control 下发布一条信息MOVE_FORWARD

mosquitto_sub¶

安装成功之后, 你可以通过mosquitto_sub 指令, 在中端获取特定Topic的数据。

mosquitto_sub -t 'pyespcar_basic_control' 综合实验¶

打开终端的两个窗口, 首先开启接收者的服务。

mosquitto_sub -t 'pyespcar_basic_control'

然后尝试在另外一个窗口发送信息:

mosquitto_pub -t 'pyespcar_basic_control' -m 'MOVE_FORWARD'

img

注: 因为Server的默认IP就是localhost, IP默认就是1883,所以这里不需要指定。 更详细的参数介绍见官方文档:

mosquitto_pub/doc

mosquitto_sub/doc

paho-mqtt¶ 安装paho-mqtt¶

另外我们还希望可以使用Python 进行基于MQTT的物联网开发, 这就需要用使用pip3安装另外一个库 paho-mqtt , 官网https://www.eclipse.org/paho/.

The Eclipse Paho project provides open-source client implementations of MQTT and MQTT-SN messaging protocols aimed at new, existing, and emerging applications for the Internet of Things (IoT).

sudo pip3 install paho-mqtt 使用paho-mqtt实现接收者¶ pc/paho-mqtt-subsriber.py import paho.mqtt.client as mqtt def on_message(client, userdata, msg): '''处理message回调''' print('topic: {}'.format(msg.topic)) print('message: {}'.format(str(msg.payload))) # 建立一个MQTT的客户端 client = mqtt.Client() # 绑定数据接收回调函数 client.on_message = on_message HOST_IP = 'localhost' # Server的IP地址 HOST_PORT = 1883 # mosquitto 默认打开端口 TOPIC_ID = 'pyespcar_basic_control' # TOPIC的ID # 连接MQTT服务器 client.connect(HOST_IP, HOST_PORT, 60) # 订阅主题 client.subscribe(TOPIC_ID) # 阻塞式, 循环往复,一直处理网络数据,断开重连 client.loop_forever() 使用paho-mqtt实现发布者¶ pc/paho-mqtt-publisher.py import paho.mqtt.client as mqtt import time HOST_IP = 'localhost' # Server的IP地址 HOST_PORT = 1883 # mosquitto 默认打开端口 TOPIC_ID = 'pyespcar_basic_control' # TOPIC的ID # 创建一个客户端 client = mqtt.Client() # 连接到服务器(本机) client.connect(HOST_IP, HOST_PORT, 60) count = 0 while True: count += 1 # 待发送的数据 message = 'MOVE FRORWORD,{}'.format(count) # 通过mqtt协议发布数据给server client.publish(TOPIC_ID, message) # 打印日志 print('SEND: {}'.format(message)) # 延时1s time.sleep(1) 综合实验¶

可以在本地的终端打开两个串口,分别输入指令:

# 运行订阅者 python3 paho-mqtt-subsriber.py # 运行发布者 python3 paho-mqtt-subsriber.py

功能其实跟上文的Mosquitto例程差不多。

paho-mqtt_pub_sub

左边是接收者的进程, 右边是发送者的进程, 这里大家留意一下,接收者在接收的时候数据打印出来是这样的:

topic: pyespcar_basic_control message: b'MOVE FRORWORD,175'

这里的b'MOVE FRORWORD,175' 是字节bytes类型的数据, 在Http通信的过程中数据以utf-8 编码的方式,传递字节数据。

通过decode方法, 可以把bytes类型的数据转换为字符串。

In [1]: bdata = b'MOVE FRORWORD,175' In [2]: bdata.decode('utf-8') Out[2]: 'MOVE FRORWORD,175' MQTT与ESP32-MicroPython¶

之前的历程都是在Ubuntu的本机上测试的, 真正的物联网怎么少的了单片机呢, 我们这里把单片机(MicroPython-ESP32)结合进来。

在ESP32上安装MQTT库¶

首先,我们需要在ESP32上面安装mqtt的库。(MQTT客户端在ESP32上面的实现)

首先确认ESP32-MicroPython已经连接上了热点!!!, 通过REPL控制ESP32。

引入upip包管理器

>>> import upip >>> upip.install('micropython-umqtt.simple') Installing to: /lib/ Installing micropython-umqtt.simple 1.3.4 from https://files.pythonhosted.org/packages/bd/cf/697e3418b2f44222b3e848078b1e33ee76aedca9b6c2430ca1b1aec1ce1d/micropython-umqtt.simple-1.3.4.tar.gz

这样umqtt.simple这个包就安装好了。

查看Server的IP地址¶

查看PC当前的IP, 在Ubuntu(作为Server)的命令行里面执行指令:

ifconfig ➜ 下载 ifconfig enp3s0 Link encap:以太网 硬件地址 5c:f9:dd:49:4b:ad UP BROADCAST MULTICAST MTU:1500 跃点数:1 接收数据包:0 错误:0 丢弃:0 过载:0 帧数:0 发送数据包:0 错误:0 丢弃:0 过载:0 载波:0 碰撞:0 发送队列长度:1000 接收字节:0 (0.0 B) 发送字节:0 (0.0 B) 中断:16 lo Link encap:本地环回 inet 地址:127.0.0.1 掩码:255.0.0.0 inet6 地址: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 跃点数:1 接收数据包:256668 错误:0 丢弃:0 过载:0 帧数:0 发送数据包:256668 错误:0 丢弃:0 过载:0 载波:0 碰撞:0 发送队列长度:1000 接收字节:138568580 (138.5 MB) 发送字节:138568580 (138.5 MB) wlp2s0 Link encap:以太网 硬件地址 68:5d:43:ec:d3:58 inet 地址:192.168.43.16 广播:192.168.43.255 掩码:255.255.255.0 inet6 地址: fe80::47ef:2ce1:f8e9:b0c2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 跃点数:1 接收数据包:146459 错误:0 丢弃:0 过载:0 帧数:0 发送数据包:137348 错误:0 丢弃:0 过载:0 载波:0 碰撞:0 发送队列长度:1000 接收字节:147948142 (147.9 MB) 发送字节:20083083 (20.0 MB)

192.168.43.16 当前PC在局域网的IP地址为

使用umqtt实现接收者¶ esp32/subscriber.py from umqtt.simple import MQTTClient import time SERVER = '192.168.43.16' CLIENT_ID = 'PYESPCAR_A0' TOPIC = b'pyespcar_basic_control' def mqtt_callback(topic, msg): print('topic: {}'.format(topic)) print('msg: {}'.format(msg)) client = MQTTClient(CLIENT_ID, SERVER) client.set_callback(mqtt_callback) client.connect() client.subscribe(TOPIC) while True: # 查看是否有数据传入 # 有的话就执行 mqtt_callback client.check_msg() time.sleep(1) 使用umqtt实现发送者¶ esp32/publisher.py from umqtt.simple import MQTTClient import time SERVER = '192.168.43.16' CLIENT_ID = 'PYESPCAR_A0' # 客户端的ID TOPIC = b'pyespcar_basic_control' # TOPIC的ID client = MQTTClient(CLIENT_ID, SERVER) client.connect() while True: client.publish(TOPIC, 'helloworld') time.sleep(1)

注意在Esp32里面TOPIC需要是bytes类型。

综合实验¶

你可以结合paho-mqtt里面的发送者与esp32里面的接收者进行测试。

也可以使用paho-mqtt里面的接收者与esp32里面的发送者进行测试。

作业¶

在PC上封装一个库,可以通过MQTT远程控制ESP32上面的LED亮灭。

上文MQTT入门之概念解析,已经把程序的整个流程列给你了。

精品课程 机械臂运动学控制及Python实现 机械臂视觉抓取从理论到实践


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3